package com.mulder.study.netty.server.demo;

import java.io.File;
import java.io.IOException;

import javax.activation.MimetypesFileTypeMap;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.WriteCompletionEvent;

import com.mulder.study.netty.NettyCommonUtil;
import com.mulder.study.netty.server.MulderNettyCommonServerHandler;

public class WebServerTestHandler extends MulderNettyCommonServerHandler
{
    private static Logger logger = Logger.getLogger(WebServerTestHandler.class);

    private String httpMethod;
    private String httpUri;
    
    private static final String WEB_ROOT = "WebRoot";
    
    private boolean closeRequested = false;
    
    @Override
    public void startupAction(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception
    {
        logger.info("client Accepted Okay");
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
                    throws Exception 
    {
        super.exceptionCaught(ctx, e);
        e.getChannel().close();
    }
    


    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
                    throws Exception 
    {
        ChannelBuffer request  = (ChannelBuffer)e.getMessage();
        byte[] message = request.readBytes(request.readableBytes()).array();
        
        logger.debug("messageReceived:\r\n" + new String(message, "utf-8"));
        
        if(!closeRequested)
        {
            for(int i=0; i<message.length; i++)
            {
                if(i>0 && message[i] == 0x0A)
                {
                    parseHttpReqeustLine (new String(message, 0, i, "utf-8"));
                    logger.debug("found CR, HttpParam: httpMethod=>" + httpMethod + ", httpUri=>" + httpUri);
                    
                    closeRequested = true;
                    handleHttpRequest (ctx, e);
                    break;
                }
            }
        }
    }
    
    
    
    @Override
    public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e) throws Exception
    {
        if(closeRequested && e.getChannel().isConnected())
        {
            logger.info("Response End!!!, Close Connection");
            e.getChannel().close();
            closeRequested = false;
            
            return;
        }
    }


    private String makeHeader(String contentType)
    {
        StringBuffer sb = new StringBuffer();
        
        sb.append("Content-Type: ").append(contentType).append("\r\n");
        for(String h : HTTP_SVR_HEADERS) 
        {
            sb.append(h).append("\r\n");
        }
        
        return sb.toString();
    }
    
    // Http Client Handler
    private void handleHttpRequest(ChannelHandlerContext ctx, MessageEvent e) throws Exception 
    {
        String filePath = WEB_ROOT + ("/".equals(httpUri) ? "/index.html" : httpUri);
        
        File f = new File(filePath);
        
        logger.debug ("request file:" + f.getAbsolutePath());
        
        if(!f.exists()) 
        {
            logger.debug("file Not Found:" + filePath);
            
            String message = "<html><head><title>Netty Tester</title></head><body><h1>File Not Found : ["+httpUri+"]</h1></body></html>\r\n\r\n";
            
            httpWrite ( ctx,  e
                , "404 Not Found", "text/html; charset=utf-8", message);
            
        }
        else
        {
            logger.debug("file Found:" + filePath);
            httpFileWrite (ctx, e, f);
        }
        
        
    }
    
    // write Text Content to HTTP Connection
    private void httpWrite (ChannelHandlerContext ctx, MessageEvent e
        , String responseMsg, String contentType, String message) throws Exception
    {
        String buffer = "HTTP/1.1 "+responseMsg + "\r\n";
        
        buffer += makeHeader(contentType);
        buffer += "Content-Length: " + message.length() + "\r\n";
        buffer += "\r\n";
        
        buffer += message;
            
        logger.info("sendOut:" + buffer);
        NettyCommonUtil.sendResponse (e.getChannel(), buffer.getBytes());
    }
    
    // write File Content to HTTP Connection 
    private void httpFileWrite(ChannelHandlerContext ctx, MessageEvent e
        ,File file) throws Exception 
    {
        String buffer = "HTTP/1.1 200 OK\r\n";
        byte[] header;
        byte[] fileContent = FileUtils.readFileToByteArray(file);
        
        String contentType = new MimetypesFileTypeMap().getContentType(file);
        
        buffer += makeHeader(contentType);
        buffer += "Content-Length: " + fileContent.length+ "\r\n";
        buffer += "\r\n";
        
        logger.info("file-download-header:" + buffer);
        
        header = buffer.getBytes();
        
        NettyCommonUtil.sendResponse (e.getChannel(), NettyCommonUtil.joinBytes(header, fileContent));
    }

    // very simple http first line parser
    private void parseHttpReqeustLine (String line) 
    {
        String[] strs = line.split(" ");
        for(int k=0; k<strs.length; k++)
        {
            if(k == 0)
            {
                httpMethod = strs[k];
            }
            else if (k == 1)
            {
                httpUri = strs[k];
            }
        }
    }
    
    

}
